
`include "axi/typedef.svh"
`include "axi/assign.svh"

module axi_cdc_top #
(
    // Width of data bus in bits
    parameter DATA_WIDTH = 32,
    // Width of address bus in bits
    parameter ADDR_WIDTH = 16,
    // Width of wstrb (width of data bus in words)
    parameter STRB_WIDTH = (DATA_WIDTH/8),
    // Width of ID signal
    parameter ID_WIDTH = 8,
    // Extra pipeline register on output
    parameter PIPELINE_OUTPUT = 0
)
(
    input  wire                   clk0,
    input  wire                   rst0,

    
    input  wire                   clk1,
    input  wire                   rst1,


    input  wire [ID_WIDTH-1:0]    s_axi_awid,
    input  wire [ADDR_WIDTH-1:0]  s_axi_awaddr,
    input  wire [7:0]             s_axi_awlen,
    input  wire [2:0]             s_axi_awsize,
    input  wire [1:0]             s_axi_awburst,
    input  wire                   s_axi_awlock,
    input  wire [3:0]             s_axi_awcache,
    input  wire [2:0]             s_axi_awprot,
    input  wire                   s_axi_awvalid,
    output wire                   s_axi_awready,
    input  wire [DATA_WIDTH-1:0]  s_axi_wdata,
    input  wire [STRB_WIDTH-1:0]  s_axi_wstrb,
    input  wire                   s_axi_wlast,
    input  wire                   s_axi_wvalid,
    output wire                   s_axi_wready,
    output wire [ID_WIDTH-1:0]    s_axi_bid,
    output wire [1:0]             s_axi_bresp,
    output wire                   s_axi_bvalid,
    input  wire                   s_axi_bready,
    input  wire [ID_WIDTH-1:0]    s_axi_arid,
    input  wire [ADDR_WIDTH-1:0]  s_axi_araddr,
    input  wire [7:0]             s_axi_arlen,
    input  wire [2:0]             s_axi_arsize,
    input  wire [1:0]             s_axi_arburst,
    input  wire                   s_axi_arlock,
    input  wire [3:0]             s_axi_arcache,
    input  wire [2:0]             s_axi_arprot,
    input  wire                   s_axi_arvalid,
    output wire                   s_axi_arready,
    output wire [ID_WIDTH-1:0]    s_axi_rid,
    output wire [DATA_WIDTH-1:0]  s_axi_rdata,
    output wire [1:0]             s_axi_rresp,
    output wire                   s_axi_rlast,
    output wire                   s_axi_rvalid,
    input  wire                   s_axi_rready,

    output  wire [ID_WIDTH-1:0]    m_axi_awid,
    output  wire [ADDR_WIDTH-1:0]  m_axi_awaddr,
    output  wire [7:0]             m_axi_awlen,
    output  wire [2:0]             m_axi_awsize,
    output  wire [1:0]             m_axi_awburst,
    output  wire                   m_axi_awlock,
    output  wire [3:0]             m_axi_awcache,
    output  wire [2:0]             m_axi_awprot,
    output  wire                   m_axi_awvalid,
    input wire                     m_axi_awready,
    output  wire [DATA_WIDTH-1:0]  m_axi_wdata,
    output  wire [STRB_WIDTH-1:0]  m_axi_wstrb,
    output  wire                   m_axi_wlast,
    output  wire                   m_axi_wvalid,
    input wire                     m_axi_wready,
    input wire [ID_WIDTH-1:0]      m_axi_bid,
    input wire [1:0]               m_axi_bresp,
    input wire                     m_axi_bvalid,
    output  wire                   m_axi_bready,
    output  wire [ID_WIDTH-1:0]    m_axi_arid,
    output  wire [ADDR_WIDTH-1:0]  m_axi_araddr,
    output  wire [7:0]             m_axi_arlen,
    output  wire [2:0]             m_axi_arsize,
    output  wire [1:0]             m_axi_arburst,
    output  wire                   m_axi_arlock,
    output  wire [3:0]             m_axi_arcache,
    output  wire [2:0]             m_axi_arprot,
    output  wire                   m_axi_arvalid,
    input wire                     m_axi_arready,
    input wire [ID_WIDTH-1:0]      m_axi_rid,
    input wire [DATA_WIDTH-1:0]    m_axi_rdata,
    input wire [1:0]               m_axi_rresp,
    input wire                     m_axi_rlast,
    input wire                     m_axi_rvalid,
    output  wire                   m_axi_rready
);

  // AXI Channel Structs

  typedef logic [ADDR_WIDTH-1:0]    addr_t;
  typedef logic [DATA_WIDTH-1:0]    data_t;
  typedef logic [ID_WIDTH-1:0]    id_t;
  typedef logic [DATA_WIDTH/8-1:0]  strb_t;
  typedef logic [2-1:0]    user_t;

  `AXI_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t)
  `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t)
  `AXI_TYPEDEF_B_CHAN_T(b_chan_t, id_t, user_t)
  `AXI_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t)
  `AXI_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t)

  AXI_BUS #(
    .AXI_ADDR_WIDTH (ADDR_WIDTH ),
    .AXI_DATA_WIDTH (DATA_WIDTH ),
    .AXI_ID_WIDTH   (ID_WIDTH   ),
    .AXI_USER_WIDTH (2)
  ) upstream ();

  AXI_BUS #(
    .AXI_ADDR_WIDTH (ADDR_WIDTH ),
    .AXI_DATA_WIDTH (DATA_WIDTH ),
    .AXI_ID_WIDTH   (ID_WIDTH   ),
    .AXI_USER_WIDTH (2)
  ) downstream ();

  
  axi_cdc_intf #(
    .AXI_ADDR_WIDTH (ADDR_WIDTH ),
    .AXI_DATA_WIDTH (DATA_WIDTH ),
    .AXI_ID_WIDTH   (ID_WIDTH   ),
    .AXI_USER_WIDTH (2),
    .LOG_DEPTH      (2)
  ) dut (
    .src_clk_i  (clk0),
    .src_rst_ni (~rst0),
    .src        (upstream),
    .dst_clk_i  (clk1),
    .dst_rst_ni (~rst1),
    .dst        (downstream)
  );



`ASSIGN_SLAVE(upstream,s_axi)
`ASSIGN_MASTER(downstream,m_axi)


endmodule

